/********************************************************************************/
/*     888888    888888888   88     888  88888   888      888    88888888       */
/*   8       8   8           8 8     8     8      8        8    8               */
/*  8            8           8  8    8     8      8        8    8               */
/*  8            888888888   8   8   8     8      8        8     8888888        */
/*  8      8888  8           8    8  8     8      8        8            8       */
/*   8       8   8           8     8 8     8      8        8            8       */
/*     888888    888888888  888     88   88888     88888888     88888888        */
/*                                                                              */
/*       A Three-Dimensional General Purpose Semiconductor Simulator.           */
/*                                                                              */
/*                                                                              */
/*  Copyright (C) 2007-2008                                                     */
/*  Cogenda Pte Ltd                                                             */
/*                                                                              */
/*  Please contact Cogenda Pte Ltd for license information                      */
/*                                                                              */
/*  Author: Gong Ding   gdiso@ustc.edu                                          */
/*                                                                              */
/********************************************************************************/

//  $Id: mesh_generation_tri3.h,v 1.11 2008/07/09 05:58:16 gdiso Exp $

#ifndef __mesh_generation_tri3_h__
#define __mesh_generation_tri3_h__

#include "mesh_generation_struct.h"

#include "triangle.h"
//#include "c_tri_io.h"

class Elem;

/**
 * the Tri3 mesh generator. it build 2d triangle mesh in XY plane
 */
class MeshGeneratorTri3 : public MeshGeneratorStruct
{
public:
  /**
   * constructor
   */
  MeshGeneratorTri3(MeshBase& mesh, Parser::InputParser & decks):
      MeshGeneratorStruct(mesh),_decks(decks),tri_cmd("pzADq30Q")
  {};


  /**
   * distructor
   */
  ~MeshGeneratorTri3()
  {
    if(point_array3d)
    {
      for(unsigned int j=0;j<IY;j++)
        delete [] point_array3d[0][j];
      delete [] point_array3d[0];
      delete [] point_array3d;
    }
  }


  /**
   * create Triangle mesh
   */
  int do_mesh();


  /**
   * refine existing mesh
   */
  int do_refine(MeshRefinement &);


  /**
   * return megh generator magic munber
   */
  unsigned int magic_num()
{ return static_cast<unsigned int>(738); }

private:
  /**
  * Reference to the input decks
  */
  Parser::InputParser & _decks;

  /**
   * the user specified region information
   */
  std::vector<SkeletonRegion2D>               region_array1d;

  /**
   * the data structure for reserved boundary edge in xy plane
   */
  std::map<SkeletonEdge, int, lt_edge>        edge_table;

  /**
   * the structure for edge information generated by Triangle code
   */
  typedef struct
  {
    int index;
    int pointno;
    int p1,p2;
    int bc_type;
    int mark;
  }
  OutEdge;

  /**
   * '<' operator for OutEdge
   */
  struct lt_oedge
  {
    bool operator()(const OutEdge &e1, const OutEdge &e2) const
    {
      unsigned long int space = e1.pointno;
      return (e1.p1 + e1.p2*space < e2.p1 + e2.p2*space );
    }
  };

  /**
   * the data structure for output segment
   */
  std::map<OutEdge, int, lt_oedge>            out_edge_table;

  /**
   * the user specified face information
   */
  std::vector<SkeletonFace>                   face_array1d;

  /**
   * triangle argument
   */
  std::string  tri_cmd;

  /**
   * build the Skeleton mesh
   */
  void build_rectangle_mesh();

  /**
   * eliminate unnecessary points in x direction
   */
  int  x_eliminate(int ixmin,int ixmax, int iymin, int iymax);

  /**
   * eliminate unnecessary points in y direction
   */
  int  y_eliminate(int iymin,int iymax, int ixmin, int ixmax);

  /**
   * disturb the regtangle mesh in y direction
   */
  int  make_spread(double center, double width,unsigned int upperline,unsigned int lowerline,
                   double yuploc,double yloloc, double y_undisturbed, double encroach,double grading);
  /**
   * renumber the nodes
   */
  void make_node_index();

  /**
   * record the boundary segment of the region
   */
  int  make_region_segment();

  /**
   * get the bc index of a Tet3 cell's side by cell's region_id,
   * and segment bc (get by p1 and p2)
   */
  int  get_bc_id(const Elem *elem, int p1, int p2);

  /**
   * set user defined boundary face (segment in 2D), user should give a label to these faces
   */
  int  make_face(int ixmin, int ixmax, int iymin,int iymax, const std::string &label);

  /**
   * set triangle io data structure
   */
  void triangulateio_init();

  /**
   * destroy triangle io data structure
   */
  void triangulateio_finalize();

  /**
   * triangle data structure
   */
#ifdef __triangle_h__
   triangulateio in, out;
#else
   CTRI::triangulateio in, out;
#endif
  /**
   * read the card "Eliminate"
   */
  int set_eliminate(const Parser::Card &c);

  /**
   * read the card "SPREAD"
   */
  int set_spread(const Parser::Card &c);

  /**
   * read the region information from card "REGION", and fills into region_array1d
   */
  int set_region(const Parser::Card &c);

  /**
   * if the shape of region is rectangle, set_region() call this function
   * to do the real work
   */
  int set_region_rectangle(const Parser::Card &c);

  /**
   * if the shape of region is ellipse, set_region() call this function
   * to do the real work
   */
  int set_region_ellipse(const Parser::Card &c);

  /**
   * read the boundary face information from card "FACE", and fills into face_array1d
   */
  int set_face(const Parser::Card &c);

  /**
   * call triangle code to generate 2D triangle mesh
   */
  int triangle_mesh();
};


#endif
